﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Threading;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using ICSharpCode.SharpZipLib.Zip;
using Metro.Core;
using Application = System.Windows.Application;
using MessageBox = System.Windows.MessageBox;

namespace MetroHome
{
    public partial class App : Application
    {
        public static readonly string Path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

        public static Settings Sett;


        //private Options options;

        public static LocaleManager LocaleManager;

        private void ApplicationDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs dispatcherUnhandledExceptionEventArgs)
        {
            Log("Unhandled exception!");
            Log(dispatcherUnhandledExceptionEventArgs.Exception.ToString());
            MessageBox.Show(dispatcherUnhandledExceptionEventArgs.Exception.Message);
            dispatcherUnhandledExceptionEventArgs.Handled = true;
        }

        public static void Log(string message)
        {
            if (!File.Exists(App.Path + "\\Logs\\log.txt"))
            {
                File.WriteAllText(App.Path + "\\Logs\\log.txt", string.Empty);
            }

            try
            {
                File.AppendAllText(App.Path + "\\Logs\\log.txt",
                   DateTime.Now + " -------------- " + message + (char)(13) + (char)(10));
            }
            catch (Exception ex)
            {
                MessageBox.Show("Can't write log. " + ex.Message);
            }
        }

        private void ApplicationStartup(object sender, StartupEventArgs e)
        {
            try
            {
                //check if we must run as administrator
                if (!Directory.Exists(Path + "\\Temp"))
                    Directory.CreateDirectory(Path + "\\Temp");
                Directory.Delete(Path + "\\Temp");
            }
            catch (UnauthorizedAccessException)
            {
                var p = new ProcessStartInfo { Verb = "runas", FileName = Assembly.GetExecutingAssembly().Location };
                Process.Start(p);
                Shutdown();
            }

            if (e.Args.Length != 0)
            {
                var skins = from x in e.Args
                            where x.EndsWith(".hhskin") && File.Exists(x)
                            select x;
                if (skins.Count() > 0)
                {
                    foreach (var s in skins)
                    {
                        Unpack(Path, s);
                        Shutdown();
                    }
                }

                var extensions = from x in e.Args
                                 where x.EndsWith(".hhext") && File.Exists(x)
                                 select x;
                if (extensions.Count() > 0)
                {
                    foreach (var ext in extensions)
                    {
                        Unpack(Path, ext);
                        Shutdown();
                    }
                }
            }

            if (!Directory.Exists(Path + "\\Config"))
                Directory.CreateDirectory(Path + "\\Config");
            if (!Directory.Exists(Path + "\\Logs"))
                Directory.CreateDirectory(Path + "\\Logs");

            Sett = Settings.Read(Path + "\\Config\\Home.conf");

            if (Sett.UseProxy)
            {
                var proxy = new WebProxy();
                proxy.Address = new Uri(Sett.ProxyAddress + ":" + Sett.ProxyPort.ToString());
                proxy.Credentials = new NetworkCredential(Sett.ProxyUsername, Sett.ProxyPassword);
                Metro.Core.GeneralHelper.Proxy = proxy;
            }

            /*if (sett.EnableUpdates && File.Exists(Path + "\\Updater.exe"))
                Process.Start(Path + "\\Updater.exe");*/

            LocaleManager = new LocaleManager(Path + "\\Localization");

            if (string.IsNullOrEmpty(Sett.Locale))
                Sett.Locale = CultureInfo.CurrentUICulture.Name;
            if (!File.Exists(Path + "\\Localization\\" + Sett.Locale + ".xaml"))
            {
                /*if (IsRemoteFileExists("http://store.htchome.org/localization/home2/" + sett.Locale + ".zip"))
                {
                    var w = new LocaleDownloadWindow(sett.Locale);
                    w.ShowDialog();
                }
                else*/
                Sett.Locale = "en-US";
            }

            LocaleManager.LoadLocale(Sett.Locale);

            try
            {
                Thread.CurrentThread.CurrentCulture = new CultureInfo(Sett.Locale);
            }
            catch { }

            Metro.Core.E.Path = Path + "\\Widgets";
            Metro.Core.E.ConfigDirectory = Path + "\\Config";
            Metro.Core.E.Locale = Sett.Locale;
            Metro.Core.E.LogDirectory = "\\Log";

        }

        private static bool IsRemoteFileExists(string url)
        {
            try
            {
                WebRequest request = HttpWebRequest.Create(url);
                request.Method = "HEAD"; // Just get the document headers, not the data.
                request.Credentials = System.Net.CredentialCache.DefaultCredentials;
                // This may throw a WebException:
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        // If no exception was thrown until now, the file exists and we 
                        // are allowed to read it. 
                        return true;
                    }
                    else
                    {
                        // Some other HTTP response - probably not good.
                        // Check its StatusCode and handle it.
                    }
                }
            }
            catch (Exception)
            {

            }
            return false;
        }

        public static void Unpack(string path, string file)
        {
            using (FileStream fileStreamIn = new FileStream(file, FileMode.Open, FileAccess.Read))
            {
                using (ZipInputStream zipInStream = new ZipInputStream(fileStreamIn))
                {
                    ZipEntry entry;
                    FileInfo info = new FileInfo(file);
                    while (true)
                    {
                        entry = zipInStream.GetNextEntry();
                        if (entry == null)
                            break;
                        if (!entry.IsDirectory)
                        {
                            if (File.Exists(path + "\\" + entry.Name))
                            {

                                File.Delete(path + "\\" + entry.Name);
                            }

                            using (FileStream fileStreamOut = new FileStream(string.Format(@"{0}\{1}", path, entry.Name), FileMode.Create, FileAccess.Write))
                            {
                                int size;
                                byte[] buffer = new byte[1024];
                                do
                                {
                                    size = zipInStream.Read(buffer, 0, buffer.Length);
                                    fileStreamOut.Write(buffer, 0, size);
                                } while (size > 0);
                                fileStreamOut.Close();
                            }
                        }
                        else
                            if (!Directory.Exists(string.Format(@"{0}\{1}", path, entry.Name)))
                                Directory.CreateDirectory(string.Format(@"{0}\{1}", path, entry.Name));
                    }
                    zipInStream.Close();
                }
                fileStreamIn.Close();
            }
        }
    }
}
